package com.cai.filter;

import com.alibaba.fastjson.JSONObject;
import com.cai.common.result.StatusCode;
import com.cai.entity.PO.UserDetailsImpl;
import com.cai.ex.ServiceException;
import com.cai.handle.ResultException;
import com.cai.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

/**
 * @Title: JwtAuthenticationTokenFilter
 * @Author RuoLi
 * @Package com.cai.filter
 * @Date 2024/1/12 14:05
 * @description: jwt过滤器
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private JwtUtils jwtUtils;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //获取请求头的token
        String token = request.getHeader("token");
        if (token == null) {
            filterChain.doFilter(request, response);
            logger.debug("请求头token为空");
            return;
        }
        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
        boolean hasKey = Boolean.TRUE.equals(redisTemplate.hasKey(token));
        boolean validate = false;
        try {
            validate = Boolean.TRUE.equals(jwtUtils.validate(token));
        } catch (Exception e) {
            ResultException.handlerException(response, StatusCode.FAIL, new ServiceException("token解析失败"));
        }
        if (!(hasKey & validate)) {
            ResultException.handlerException(response, StatusCode.FAIL, new ServiceException("token未携带或无效"));
            return;
        }
        //解析token
        Claims claims = jwtUtils.parseToken(token);
        String userId = claims.getSubject();
        //获取用户数据在缓存中查询用户数据
        if (Objects.isNull(userId)) {
            ResultException.handlerException(response, StatusCode.FAIL, new ServiceException("数据查询失败，请重新登录"));
            return;
        }
        Object userDetailsCacheImpl = opsForValue.get("login:" + userId);
        if (Objects.isNull(userDetailsCacheImpl)) {
            ResultException.handlerException(response, StatusCode.FAIL, new ServiceException("数据查询失败，请重新登录"));
            return;
        }
        UserDetailsImpl userDetails = JSONObject.parseObject(String.valueOf(userDetailsCacheImpl), UserDetailsImpl.class);
        //持久化保存在SecurityContextHolder中
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        logger.debug("jwt过滤器通过");
        filterChain.doFilter(request, response);
    }
}
